package net.villonanny.entity;

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.villonanny.ConversationException;
import net.villonanny.EventLog;
import net.villonanny.TimeWhenRunnable;
import net.villonanny.Translator;
import net.villonanny.Util;
import net.villonanny.type.ResourceType;
import net.villonanny.type.ResourceTypeMap;
import net.villonanny.type.TroopType;
import net.villonanny.type.TroopTypeMap;

import org.apache.log4j.Logger;

public class TrainerSite extends Building {
	private final static Logger log = Logger.getLogger(TrainerSite.class);
	
	private Map<TroopType, Integer> troopTrainMax; // Troops that can be produced
	
	private EnumMap<TroopType, ResourceTypeMap> troopCost;
	
	private Map<TimeWhenRunnable, TroopTypeMap> producingTroop; // Troops currently in production
	
	public TrainerSite(String name, String urlString, Translator translator) {
		super(name, urlString, translator);
	}

	public void fetch(Util util) throws ConversationException {
		super.fetch(util);
		troopTrainMax = new HashMap<TroopType, Integer>();
		troopCost = new EnumMap<TroopType, ResourceTypeMap>(TroopType.class);
		producingTroop = new HashMap<TimeWhenRunnable, TroopTypeMap>();

		Pattern p;
		Matcher m;
		String page = util.httpGetPage(getUrlString());

		// 1 - Troop name 
		// 2 - Wood Cost
		// 3 - Clay Cost
		// 4 - Iron Cost
		// 5 - Crop Cost
		// 6 - Food Cost
		// 7 - Max Production available
		p = Pattern.compile("(?s)(?i)<table[^>]+class=\"f10[^>]+>.*?<a[^>]+onClick[^>]+>([^<]*)</a>.*?<img[^>]*class=\"r1\"[^>]+>(\\d+)[^<]*<img[^>]*class=\"r2\"[^>]+>(\\d+)[^<]*<img[^>]*class=\"r3\"[^>]+>(\\d+)[^<]*<img[^>]*class=\"r4\"[^>]+>(\\d+)[^<]*<img[^>]*class=\"r5\"[^>]+>(\\d+).*?<a[^>]*onClick=\"document.snd.t\\d+.value=\\d+; return false;\">\\((\\d+)\\)</a></div>");

		// The use above of .*? instead of .* makes the difference 
		m = p.matcher(page);
		int lastMatchPos=0;
		while (m.find()) {
			lastMatchPos = m.end();
			String troopName = m.group(1).trim();
			String stringNumber1 = m.group(2);
			String stringNumber2 = m.group(3);
			String stringNumber3 = m.group(4);
			String stringNumber4 = m.group(5);
			String stringNumber5 = m.group(6);
			String maxProd = m.group(7);
			ResourceTypeMap resources = new ResourceTypeMap();
			try {
				String fullkey = util.getTranslator().getKeyword(troopName); // romans.troop1
				String typeKey = fullkey.substring(fullkey.indexOf(".") + 1);
				TroopType troopType = TroopType.fromString(typeKey);
				resources.put(ResourceType.WOOD, Integer.valueOf(stringNumber1));
				resources.put(ResourceType.CLAY, Integer.valueOf(stringNumber2));
				resources.put(ResourceType.IRON, Integer.valueOf(stringNumber3));
				resources.put(ResourceType.CROP, Integer.valueOf(stringNumber4));
				resources.put(ResourceType.FOOD, Integer.valueOf(stringNumber5));
				troopCost.put(troopType, resources);
				troopTrainMax.put(troopType, Integer.valueOf(maxProd));
				log.debug("Trainable troop: " + troopName);
			} catch (NumberFormatException nfe) {
				log.error("Problem parsing troop costs", nfe);
				throw new ConversationException("Problem parsing troop costs in " + this.getName());
			}
		}
		
		// 1 - Troop quantity
		// 2 - Troop name
		// 3 - Time to finish
		// <img class="unit" src="img/un/u/2.gif" border="0"></td>
		// <td width="6%" align="right">89&nbsp;</td>
		// <td width="39%" class="s7">Praetorian</td>
		// <td width="25%"><span id=timer2>2:42:00</span></td>
		p = Pattern.compile("(?s)(?i)<img[^>]*class=\"unit[^>]+></td>\\s*<td[^>]+>(\\d+)&nbsp;</td>\\s*<td[^>]+>([^<]+)</td>\\s*<td[^>]+><span id=timer2>([^<]+)</span></td>");
		m = p.matcher(page);
		m.region(lastMatchPos, page.length());
		while (m.find()) {
			String stringNumer = m.group(1);
			String troopName = m.group(2);
			String timeString = m.group(3);
			try {
				String fullkey = util.getTranslator().getKeyword(troopName); // romans.troop1
				String typeKey = fullkey.substring(fullkey.indexOf(".") + 1);
				TroopType troopType = TroopType.fromString(typeKey);
				TimeWhenRunnable trainFinishTime = new TimeWhenRunnable(System.currentTimeMillis() + Util.timeToSeconds(timeString));
				TroopTypeMap trainingGroup = new TroopTypeMap();
				trainingGroup.put(troopType, Integer.getInteger(stringNumer));
				producingTroop.put(trainFinishTime, trainingGroup);
				log.debug("Currrently training troops: " + troopType.toString());
			} catch (NumberFormatException nfe) {
				log.error("Problem parsing traning troops in", nfe);
				throw new ConversationException("Problem parsing traning troops in " + this.getName());
			}
		}
	}
	
	public void trainTroop(Util util, TroopType type, int value, boolean quick) throws ConversationException {
		TroopTypeMap troop = new TroopTypeMap();
		troop.put(type, value);
		
		trainTroops(util, troop, quick);
	}
	
	public void trainTroops(Util util, TroopTypeMap troops, boolean quick) throws ConversationException {
		String page;
		StringBuffer trainedTroops = null;
		TroopTypeMap trainTroops = new TroopTypeMap();
		
		// Go to troop transfer page
		page = util.httpGetPage(getUrlString());
		List<String> postNames = new ArrayList<String>();
		List<String> postValues = new ArrayList<String>();

		// Find hidden fields
		//Util.addHiddenPostFields(page, "<form method=\"POST\" name=\"snd\" action=\"build.php\">", postNames, postValues);
		Util.addHiddenPostFields(page, "<form[^>]+ action=\"build.php\">", postNames, postValues);
		Util.addButtonCoordinates("s1", 80, 20, postNames, postValues);
		
		// Add troop amounts
		for (TroopType type : troops.keySet()) {
			if (troops.get(type).intValue() <= 0) {
				continue;
			}
			int troopsValue = troops.get(type);
			// Check if the troop building site is this one
			if (type.getBuilding() == getType()) {
				// Check if the amount of troops to be trained is bigger than what we can train
				trainTroops.put(type, Math.max(Math.min(getTroopTrainMax(type).intValue(), troopsValue), 0));
				if (trainTroops.get(type) > 0) {
					if (trainedTroops == null) {
						trainedTroops = new StringBuffer(type.toString());
					} else {
						trainedTroops.append("; ");
						trainedTroops.append(type.toString());
					}
				}
			}
		}
		if (trainedTroops == null) {
			EventLog.log("No troops to be done");
			return;
		}

		// Convert to string post values
		for (TroopType troopTypes : TroopType.values()) {
			int toSend = trainTroops.get(troopTypes);
			postNames.add("t" + (troopTypes.toInt()+1));
			if (toSend>0) {
				postValues.add(Integer.toString(toSend));
			} else {
				postValues.add("");
			}
		}
		
		// post
		page = util.httpPostPage(getUrlString(), postNames, postValues, quick);
		EventLog.log("Making troops " + trainedTroops.toString());
	}

	public Integer getTroopTrainMax(TroopType type) {
		return troopTrainMax.get(type);
	}

	public ResourceTypeMap getTroopCost(TroopType type) {
		return troopCost.get(type);
	}
	
}
